using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Security.Permissions;

namespace C4F.DevKit.PreviewHandler.PreviewHandlerHostSample
{
    public partial class ExplorerForm : Form
    {
        public const uint SHGFI_ICON = 0x100;         // Gets the icon 
        public const uint SHGFI_DISPLAYNAME = 0x200;  // Gets the Display name
        public const uint SHGFI_TYPENAME = 0x400;     // Gets the type name
        public const uint SHGFI_LARGEICON = 0x0;      // Large icon
        public const uint SHGFI_SMALLICON = 0x1;      // Small icon

        private const string IMAGE_FOLDER_KEY = "Folder";
        private const int MAX_LOCATION_HISTORY = 5;
        private List<string> _locations = new List<string>(MAX_LOCATION_HISTORY);
        private int _locationPosition = 0;
        private bool isForward = false;
        private bool isBack = false;

        public ExplorerForm()
        {
            InitializeComponent();
        }        

        #region Methods

        #region Private

        private void InitializeFolderList()
        {
            string[] drives = Environment.GetLogicalDrives();

            foreach (string drive in drives)
            {
                TreeNode node = new TreeNode();
                node.Text = drive;
                node.Name = drive;
                
                trvFolderList.Nodes.Add(node);
            }
        }

        private void JumpToNode(string path)
        {
            trvFolderList.SelectedNode = trvFolderList.SelectedNode.Nodes[path];
        }

        private bool IsDirectory(FileSystemInfo info)
        {
            return (info.Attributes & FileAttributes.Directory) == FileAttributes.Directory;
        }

        private bool IsHidden(FileSystemInfo info)
        {
            return (info.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden;
        }

        #endregion Private

        #region Protected

        #endregion Protected

        #region Eventhandlers

        private void ExplorerForm_Load(object sender, EventArgs e)
        {
            InitializeFolderList();
        }

        private void trvFolderList_AfterSelect(object sender, TreeViewEventArgs e)
        {
            try
            {

                DirectoryInfo[] dirList = new DirectoryInfo((string)e.Node.Name).GetDirectories();

                lvwFiles.Items.Clear();
                imageList1.Images.Clear();
                e.Node.Nodes.Clear();

                foreach (DirectoryInfo dir in dirList)
                {
                    if (!IsHidden(dir))
                    {
                        SHFILEINFO info = ExplorerForm.GetFileInfo(dir.FullName);
                        imageList1.Images.Add(dir.Name, System.Drawing.Icon.FromHandle(info.hIcon));

                        ListViewItem item = lvwFiles.Items.Add(dir.Name, dir.Name);

                        item.Tag = dir.FullName;

                        TreeNode node = new TreeNode();
                        node.Text = dir.Name;
                        node.Name = dir.FullName;
                        node.ImageKey = IMAGE_FOLDER_KEY;
                        e.Node.Nodes.Add(node);
                    }
                }

                FileInfo[] fileList = new DirectoryInfo((string)e.Node.Name).GetFiles();

                foreach (FileInfo file in fileList)
                {
                    if (!IsHidden(file))
                    {
                        SHFILEINFO info = ExplorerForm.GetFileInfo(file.FullName);

                        imageList1.Images.Add(file.Name, System.Drawing.Icon.FromHandle(info.hIcon));

                        ListViewItem item = lvwFiles.Items.Add(file.Name, file.Name);
                        item.SubItems.Add(new ListViewItem.ListViewSubItem(item, string.Format("{0} {1}", file.LastWriteTime.ToShortDateString(), file.LastWriteTime.ToShortTimeString())));
                        item.SubItems.Add(new ListViewItem.ListViewSubItem(item, info.szTypeName));
                        item.SubItems.Add(new ListViewItem.ListViewSubItem(item, (file.Length / 1000).ToString("N0") + " KB"));
                        item.Tag = file.FullName;
                    }
                }

                txtLocation.Text = trvFolderList.SelectedNode.Name;

                if (!isBack && !isForward)
                {
                    if (_locationPosition < _locations.Count)
                    {
                        for (int i = _locationPosition; i < _locations.Count; i++)
                        {
                            _locations.RemoveAt(i);
                        }
                    }
                    if (_locations.Count == MAX_LOCATION_HISTORY)
                    {
                        _locations.RemoveAt(0);
                        _locationPosition--;
                    }

                    _locations.Add(txtLocation.Text);
                    _locationPosition++;
                }
                if (_locationPosition == 1)
                {
                    tsbBack.Enabled = false;
                }
                else
                {
                    tsbBack.Enabled = true;
                }
                if (_locations.Count > _locationPosition)
                {
                    tsbForward.Enabled = true;
                }
                else
                {
                    tsbForward.Enabled = false;
                }
                if (trvFolderList.SelectedNode.Parent == null)
                {
                    tsbUp.Enabled = false;
                }
                else
                {
                    tsbUp.Enabled = true;
                }
                isBack = false;
                isForward = false;
            }
            catch (Exception)
            { }


        }

        private void lvwFiles_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lvwFiles.SelectedItems.Count == 1)
            {
                ListViewItem selectedItem = lvwFiles.SelectedItems[0];
                FileInfo file = new FileInfo(selectedItem.Tag.ToString());

                if (!IsDirectory(file))
                {
                    try
                    {
                        PreviewHandlerHostControl1.FilePath = file.FullName;
                    }
                    catch (Exception anexception)
                    {

                    }
                }
            }
        }

        private void lvwFiles_DoubleClick(object sender, EventArgs e)
        {
            try
            {
                if (lvwFiles.SelectedItems.Count == 1)
                {
                    string path = lvwFiles.SelectedItems[0].Tag.ToString();

                    if (Directory.Exists(path))
                        JumpToNode(path);
                        
                }
            }
            catch (Exception)
            {
                // TODO: Add error message somewhere
            }
        }

        private void tsbUp_Click(object sender, EventArgs e)
        {
            try
            {
                if (trvFolderList.SelectedNode.Parent != null)
                    trvFolderList.SelectedNode = trvFolderList.SelectedNode.Parent;
            }
            catch (Exception)
            {
                // TODO: Do something about error
            }
        }

        #endregion EventHandlers

        #endregion Methods

        [DllImport("shell32.dll")]
        public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);

        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public static SHFILEINFO GetFileInfo(string path)
        {
            SHFILEINFO info = new SHFILEINFO();
            IntPtr icon;

            icon = SHGetFileInfo(path, 0, ref info, (uint)Marshal.SizeOf(info), SHGFI_ICON | SHGFI_TYPENAME | SHGFI_SMALLICON);

            return info;
        }

        private void txtLocation_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                if (trvFolderList.Nodes.Find(txtLocation.Text, true).Length > 0)
                {
                    trvFolderList.SelectedNode = trvFolderList.Nodes.Find(txtLocation.Text, true)[0];
                }
            }
        }

        private void tsbGo_Click(object sender, EventArgs e)
        {
            if (trvFolderList.Nodes.Find(txtLocation.Text, true).Length > 0)
            {
                trvFolderList.SelectedNode = trvFolderList.Nodes.Find(txtLocation.Text, true)[0];
            }

        }

        private void tsbBack_Click(object sender, EventArgs e)
        {
            if (_locationPosition > 1 && trvFolderList.Nodes.Find(_locations[_locationPosition-1], true).Length > 0)
            {
                isBack = true;
                _locationPosition--;
                trvFolderList.SelectedNode = trvFolderList.Nodes.Find(_locations[_locationPosition - 1], true)[0];
            }

        }

        private void tsbForward_Click(object sender, EventArgs e)
        {
            if ((_locations.Count > _locationPosition) && trvFolderList.Nodes.Find(_locations[_locationPosition], true).Length > 0)
            {
                isForward = true;
                _locationPosition++;
                trvFolderList.SelectedNode = trvFolderList.Nodes.Find(_locations[_locationPosition-1], true)[0];
            }

        }                
    }

    public struct SHFILEINFO
    {
        public IntPtr hIcon;
        public IntPtr iIcon;
        public uint dwAttributes;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string szDisplayName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
        public string szTypeName;
    };
}